package main

import (
	"fmt"

	"github.com/klauspost/reedsolomon"
)
//RS纠错算法：

// https://www.backblaze.com/blog/reed-solomon/
// https://blog.csdn.net/wangsiman/article/details/80101654
// https://zhuanlan.zhihu.com/p/104306038

// 很多年前，大约还在学校的时候，我曾有些疑问：磁头在读磁盘信息的时候如果不小心读错一个字节怎么办？为什么一个光盘即使有一些污渍，
// 依然可以正确地读取出来内容？
//
// 前几个月当我看到ECC这个算法的时候，我张大了嘴~~~~~~
//
// 信息在传输的过程中是不能保证无错误的，就如同相机拍照永远都会有噪声一样。
//
// 有意思的地方在于，牛逼数学大师们解决了这样的传输错误问题，我们现在知道的所有有关信息传输存储读取相关的技术都有ECC的身影。
//
// ECC的算法们，太牛逼了。它让整个世界可以无错地运转起来。
//
// 在这里，我会介绍一下ECC领域里一个牛逼的算法：RS纠错算法。

func main() {
	data := make([][]byte, 13)
	for k := range data {
		data[k] = []byte(fmt.Sprintf("%02d", k)) // same size
	}

	for _, v := range data {
		fmt.Printf("%02s ", string(v))
	}
	fmt.Println("=============")

	enc, err := reedsolomon.New(10, 3)
	if err != nil {
		panic(err)
	}

	if err := enc.Encode(data); err != nil {
		panic(err)
	}

	if ok, err := enc.Verify(data); !ok || err != nil {
		panic(err)
	}

	fmt.Println("reconstruct:")
	{
		// missing packet
		data[1] = nil
		data[2] = nil
		// missing parity packet
		data[11] = nil
		// data[3] = []byte("xx") // cann't reconstruct missing data

		for _, v := range data {
			fmt.Printf("%02s ", string(v))
		}
		fmt.Println("before")

		// rebuild
		if err := enc.Reconstruct(data); err != nil {
			panic(err)
		}

		for _, v := range data {
			fmt.Printf("%02s ", string(v))
		}
		fmt.Println("after")
	}

	fmt.Println("reconstruct data:")
	{
		// missing packet
		data[1] = nil
		data[2] = nil
		// missing parity packet
		data[11] = nil
		// data[3] = []byte("xx") // cann't reconstruct missing data

		for _, v := range data {
			fmt.Printf("%02s ", string(v))
		}
		fmt.Println("before")

		// rebuild; expect parity packet
		if err := enc.ReconstructData(data); err != nil {
			panic(err)
		}

		for _, v := range data {
			fmt.Printf("%02s ", string(v))
		}
		fmt.Println("after")
	}
}
